package pers.yurwisher.rubick.oauth2.support;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.DefaultJSONParser;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.TokenRequest;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author yq
 * @date 2021/04/18 16:48
 * @since V1.0.0 使用fastjson 序列化OAuth2Authentication 需自定义反序列化类,否则 OAuth2Request 反序列化无效
 * @description
 */
public class CustomOAuth2AuthenticationSerializer implements ObjectDeserializer {


    @Override
    @SuppressWarnings("unchecked")
    public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        if (type == OAuth2Authentication.class) {
            try {
                //初次转化 OAuth2Request 为 jsonObject对象
                JSONObject jsonObject = (JSONObject) parser.parseObject(new JSONObject(parser.lexer.isEnabled(Feature.OrderedField)));
                //再次序列化
                OAuth2Request request = parseOAuth2Request(jsonObject);

                //判断json节点userAuthentication的类型，根据类型动态取值
                //UsernamePasswordAuthenticationToken 密码模式/授权码模式下，存储类型为UsernamePasswordAuthenticationToken
                //PreAuthenticatedAuthenticationToken 刷新token模式下，存储类型为PreAuthenticatedAuthenticationToken
                Object autoType = jsonObject.get("userAuthentication");
                return (T) new OAuth2Authentication(request, jsonObject.getObject("userAuthentication", (Type) autoType.getClass()));
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
        return null;
    }

    private OAuth2Request parseOAuth2Request(JSONObject jsonObject) {
        JSONObject json = jsonObject.getJSONObject("oAuth2Request");
        Map<String, String> requestParameters = json.getObject("requestParameters", Map.class);
        String clientId = json.getString("clientId");
        String grantType = json.getString("grantType");
        String redirectUri = json.getString("redirectUri");
        Boolean approved = json.getBoolean("approved");
        TypeReference<HashSet<String>> typeReference = new TypeReference<HashSet<String>>() {
        };
        Set<String> responseTypes = json.getObject("responseTypes", typeReference);
        Set<String> scope = json.getObject("scope", typeReference);
        Set<String> authorities = json.getObject("authorities", typeReference);
        Set<GrantedAuthority> grantedAuthorities = new HashSet<>(0);
        if (authorities != null && !authorities.isEmpty()) {
            authorities.forEach(s -> grantedAuthorities.add(new SimpleGrantedAuthority(s)));
        }
        Set<String> resourceIds = json.getObject("resourceIds", typeReference);
        Map<String, Serializable> extensions = json.getObject("extensions", new TypeReference<HashMap<String, Serializable>>() {
        });

        OAuth2Request request = new OAuth2Request(requestParameters, clientId, grantedAuthorities, approved, scope, resourceIds, redirectUri, responseTypes, extensions);
        TokenRequest tokenRequest = new TokenRequest(requestParameters, clientId, scope, grantType);
        request.refresh(tokenRequest);
        return request;
    }


    @Override
    public int getFastMatchToken() {
        return 0;
    }

}
